﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using ApplicationCore;
using UserSurface;

namespace EnzymeLaborTool.View.Controls
{
    public partial class BachtLayoutCtrl : UserControl
    {
        public BachtLayoutCtrl()
        {
            InitializeComponent();
            layoutDataGridView.CellValidating += new DataGridViewCellValidatingEventHandler(kryptonDataGridViewLayout_CellValidating);
            layoutDataGridView.EditingControlShowing += new DataGridViewEditingControlShowingEventHandler(kryptonDataGridViewLayout_EditingControlShowing);
            layoutDataGridView.CellFormatting += new DataGridViewCellFormattingEventHandler(kryptonDataGridViewLayout_CellFormatting);
            layoutDataGridView.CellEndEdit += new DataGridViewCellEventHandler(kryptonDataGridViewLayout_CellEndEdit);
        }

        //validate cell content
        void kryptonDataGridViewLayout_CellValidating(object sender, DataGridViewCellValidatingEventArgs e)
        {
            if (layoutDataGridView.IsCurrentCellDirty)
            {
                string error;
                if (!_currentLayout.ValidateEntry(e.FormattedValue.ToString(), out error))
                {
                    layoutDataGridView.Rows[e.RowIndex].ErrorText = error;
                    e.Cancel = true;
                }
            }
        }

        //copy data down to model and reflect if SPLIT layout
        void kryptonDataGridViewLayout_CellEndEdit(object sender, DataGridViewCellEventArgs e)
        {
            layoutDataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].ErrorText = null;
            layoutDataGridView.Rows[e.RowIndex].ErrorText = null;
            string newVal;
            if (layoutDataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].Value != null)
                newVal = layoutDataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].Value.ToString();
            else
                newVal = null;
            if (_currentLayout.Layout[e.RowIndex, e.ColumnIndex] != newVal)
            {
                _currentLayout.Layout[e.RowIndex, e.ColumnIndex] = newVal;
                layoutSaveButton.Enabled = true;
            }
            if (SHOWFULLLAYOUT && _currentLayout != null && _currentLayout.LayoutType == "SPLIT" && e.RowIndex < _currentLayout.Layout.GetLength(0))
            {
                layoutDataGridView.Rows[e.RowIndex + _currentLayout.Layout.GetLength(0)].Cells[e.ColumnIndex].Value = layoutDataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].Value;
            }
            UnSavedChanges = true;
        }

        //color cells depending on the content
        void kryptonDataGridViewLayout_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
        {

            if (!backgroundWorkerLoader.IsBusy)
            {
                if (e.Value != null)
                    e.CellStyle.BackColor = _surface.CurrenBatchLayoutA.Entry2Color(e.Value.ToString());
                else
                    e.CellStyle.BackColor = Color.White;
                if (_currentLayout != null && _currentLayout.LayoutType == "SPLIT" && e.RowIndex >= _currentLayout.Layout.GetLength(0))
                {
                    e.CellStyle.ForeColor = Color.DarkGray;
                }
            }
        }

        internal void InvalidateDataContext(bool restorePosition = true)
        {
            _forceAutocompleteRefresh = true;
        }

        private MainSurface _surface;
        //private EnzymeDBDataContext _dataContext;
        public void Init(MainSurface ms)
        {
            _surface = ms;
            //_dataContext = ms.GetDataContext();
            _surface.CurrenBatchLayoutA.Validation += new EventHandler<ValidationErrorEventArgs>(CurrenBatchLayout_Validation);
        }

        #region SECURITY
        private void ApplySecurity()
        {
            layoutDataGridView.Enabled = false;
            pasteLayoutButton.Enabled = false;
            layoutSaveButton.Enabled = false;

            if (_surface.SecDescriptor.Rights.ContainsKey("BatchCompilation"))
            {
                foreach (TableRight tr in _surface.SecDescriptor.Rights["BatchCompilation"])
                {
                    switch (tr)
                    {
                        case TableRight.Insert:
                            {

                                layoutDataGridView.Enabled = true;
                                pasteLayoutButton.Enabled = true;
                                layoutSaveButton.Enabled = true;
                                break;
                            }
                        case TableRight.Delete:
                            {
                                break;
                            }
                        case TableRight.Update:
                            {
                                layoutDataGridView.Enabled = true;
                                pasteLayoutButton.Enabled = true;
                                layoutSaveButton.Enabled = true;
                                break;
                            }
                    }
                }
            }
        }

        #endregion

        void CurrenBatchLayout_Validation(object sender, ValidationErrorEventArgs e)
        {
            layoutDataGridView.Rows[e.Row].Cells[e.Column].ErrorText += e.Message;
        }

        private string[] _lastAutoCompleteSource;
        private string[] CreateAutoCompleteSource(bool forceRefresh)
        {
            if (_lastAutoCompleteSource == null || forceRefresh)
            {
                _lastAutoCompleteSource = _surface.CurrentDataContext.FreshWeightViews
                    .AsParallel()
                    .AsUnordered()
                    .Where(x => x.State != "in use" && x.ExperimentId != "EB" && x.ExperimentId != "?")
                    .Select(x => new { ExperimentId = x.ExperimentId, Sample = x.Sample, Aliquot = x.Aliquot })
                    .Distinct()
                    .OrderBy(x => x.ExperimentId)
                    .ThenBy(x => x.Sample)
                    .ThenBy(x => x.Aliquot)
                    .Select(x => String.Join("-", x.ExperimentId, x.Sample, x.Aliquot))
                    .ToArray();
            }
            return _lastAutoCompleteSource;
        }

        void kryptonDataGridViewLayout_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
        {
            TextBox tb = e.Control as TextBox;
            tb.AutoCompleteMode = AutoCompleteMode.SuggestAppend;
            tb.AutoCompleteSource = AutoCompleteSource.CustomSource;
            tb.AutoCompleteCustomSource.Clear();
            tb.AutoCompleteCustomSource.AddRange(CreateAutoCompleteSource(false));
        }

        //loads the batch layout async

        private DateTime _start;
        public void NavigateBatchLayout(BatchView bv)
        {
            layoutDataGridView.EndEdit(); //end pending edit mode

            if (!backgroundWorkerLoader.IsBusy)
            {
                _start = DateTime.Now;
                progressBar1.Visible = true;
                backgroundWorkerLoader.RunWorkerAsync(bv);
            }
        }

        private string _headerStr = "96 well plate - {0} Layout";
        private BatchLayout _currentLayout;

        private const bool SHOWFULLLAYOUT = true;
        //configures the datagridview depending on the batch layout

        private bool _forceAutocompleteRefresh = false;
        private void LoadLayout()
        {
            _currentLayout = _surface.CurrenBatchLayoutA;
            kryptonHeader1.Values.Heading = string.Format(_headerStr, _currentLayout.LayoutType);
            kryptonHeader1.Values.Description = _surface.CurrenBatchLayoutA.BatchName;

            DataGridHelper.Configure(layoutDataGridView, _currentLayout, SHOWFULLLAYOUT);
            TimeSpan stop2 = DateTime.Now - _start;
            System.Diagnostics.Debug.WriteLine("Grid configured after {0}", stop2);

            LoadData();
            TimeSpan stop3 = DateTime.Now - _start;
            System.Diagnostics.Debug.WriteLine("Load data to Grid  after {0}", stop3);

            CreateAutoCompleteSource(_forceAutocompleteRefresh);
            _forceAutocompleteRefresh = false;
            TimeSpan stop4 = DateTime.Now - _start;
            System.Diagnostics.Debug.WriteLine("Autocomplet data loaded and done after {0}", stop4);
            UnSavedChanges = false;
        }

        private void LoadData()
        {
            DataGridHelper.LoadData(layoutDataGridView, _currentLayout);
            if (SHOWFULLLAYOUT && _currentLayout.LayoutType == "SPLIT")
            {
                DataGridHelper.RepeatRows(layoutDataGridView);
            }
        }

        private void backgroundWorkerLoader_DoWork(object sender, DoWorkEventArgs e)
        {
            BatchView bv = e.Argument as BatchView;
            _surface.NavigateBatchA(bv);
            TimeSpan stop1 = DateTime.Now - _start;
            System.Diagnostics.Debug.WriteLine("NavigateBatch on MainSurface done after {0}", stop1);
        }

        private void backgroundWorkerLoader_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            LoadLayout();
            progressBar1.Visible = false;
            layoutSaveButton.Enabled = false;
        }

        private void layoutValidateButton_Click(object sender, EventArgs e)
        {
            ClearValidationErrors();
            _currentLayout.ValidateAll();
        }

        private void ClearValidationErrors()
        {
            foreach (DataGridViewRow row in layoutDataGridView.Rows)
            {
                row.ErrorText = null;
                foreach (DataGridViewCell item in row.Cells)
                {
                    item.ErrorText = null;
                }
            }
        }

        private void OnSaveLayout(object sender, EventArgs e)
        {
            _forceAutocompleteRefresh = true;
            ClearValidationErrors();
            if (_currentLayout.ValidateAll())
            {
                _currentLayout.SaveLayout();

                UnSavedChanges = false;
            }
        }

        private void OnFillWithUnknowns(object sender, EventArgs e)
        {
            int maxI = _currentLayout.Layout.GetLength(0);
            int maxJ = _currentLayout.Layout.GetLength(1);

            bool cellsFilled = false;
            for (int i = 0; i < maxI; i++)
            {
                for (int j = 0; j < maxJ; j++)
                {
                    if (String.IsNullOrEmpty(_currentLayout.Layout[i, j]))
                    {
                        _currentLayout.Layout[i, j] = "?";
                        cellsFilled = true;
                    }
                }
            }
            if (cellsFilled)
            {
                ClearValidationErrors();
                _currentLayout.ValidateAll();
                LoadData();
                UnSavedChanges = true;
            }
        }

        private void OnCopyToClipboard(object sender, EventArgs e)
        {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < _currentLayout.Layout.GetLength(0); i++)
            {
                for (int j = 0; j < _currentLayout.Layout.GetLength(1); j++)
                {
                    sb.AppendFormat("{0}{1}", _currentLayout.Layout[i, j], '\t');
                }
                sb.Remove(sb.Length - 1, 1);
                sb.Append("\r\n");
            }
            sb.Remove(sb.Length - 2, 2);
            Clipboard.SetText(sb.ToString());
        }

        private void OnPasteFromClipboard(object sender, EventArgs e)
        {
            if (Clipboard.ContainsText())
            {
                string[,] layout = ParseClipboardContent(Clipboard.GetText());
                bool dataCopied = false;
                for (int i = 0; i < layout.GetLength(0) && i < _currentLayout.Layout.GetLength(0); i++)
                {
                    for (int j = 0; j < layout.GetLength(1) && j < _currentLayout.Layout.GetLength(1); j++)
                    {
                        _currentLayout.Layout[i, j] = layout[i, j];
                        dataCopied = true;
                    }
                }
                if (dataCopied)
                {
                    ClearValidationErrors();
                    _currentLayout.ValidateAll();
                    LoadData();
                    UnSavedChanges = true;
                }
            }
        }

        /// <summary>
        /// Read the clipboard text to a matrix
        /// </summary>
        /// <param name="content">The clipboard text</param>
        /// <returns>The resulting matrix.</returns>
        private string[,] ParseClipboardContent(string content)
        {
            int maxcolumn = 0;
            string[] lines = content.Split("\r\n".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
            foreach (string s in lines)
            {
                int cols;
                cols = s.Split('\t').Length;
                if (cols > maxcolumn)
                    maxcolumn = cols;
            }
            string[,] r = new string[lines.Length, maxcolumn];

            for (int i = 0; i < lines.Length; i++)
            {
                string[] line;
                line = lines[i].Split('\t');
                for (int j = 0; j < maxcolumn; j++)
                {
                    r[i, j] = line[j];
                }
            }
            return r;
        }

        private bool _unsavedChanges;
        public bool UnSavedChanges
        {
            get
            {
                return _unsavedChanges;
            }
            set
            {
                _unsavedChanges = value;
                layoutSaveButton.Enabled = value;

                if (UnSavedChangesChanged != null)
                {
                    UnSavedChangesChanged(this, EventArgs.Empty);
                }
            }
        }


        public event EventHandler UnSavedChangesChanged;

        internal void InvalidateCurrentView()
        {
            //throw new NotImplementedException();
        }

        private void layoutDataGridView_CellEnter(object sender, DataGridViewCellEventArgs e)
        {
            if (!string.IsNullOrEmpty(layoutDataGridView[e.ColumnIndex, e.RowIndex].ErrorText))
            {
                OnStatusChanged(layoutDataGridView[e.ColumnIndex, e.RowIndex].ErrorText);
            }
            else
            {
                OnStatusChanged(string.Empty);
            }
        }

        private void OnStatusChanged(string status)
        {
            if (this.StatusChanged != null)
            {
                StatusChanged(this, new StatusChangedEventArgs(status));
            }
        }

        public event EventHandler<StatusChangedEventArgs> StatusChanged;
    }
}
